// ------------------------------------------------------------------------
// 版权信息
// 版权归重庆虫儿飞科技有限公司所有。
// 所有权利保留。
// 官方网站：https://netokit.com
// 许可证信息
// Neto.Kit 项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// 
// 使用条款
// 使用本代码应遵守相关法律法规和许可证的要求。
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Neto.Kit 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// 有关 Neto.Kit 项目的其他详细信息，请参阅位于源代码树根目录中的 COPYRIGHT 和 DISCLAIMER 文件。
// 
// 更多信息
// 请访问 https://netokit.com 获取更多关于 Neto.Kit 项目的许可证和版权信息。
// ------------------------------------------------------------------------

#region

using System.Text.RegularExpressions;

#endregion

namespace Neto.CodeGeneration;

/// <summary>
///     代码帮助类
/// </summary>
[SuppressSniffer]
internal class CgCodeInternal
{
    /// <summary>
    ///     获取CodeType
    ///     【此数据从Sqlsugar的webfirst的数据库中复制出来的】
    /// </summary>
    /// <returns></returns>
    internal static List<CgCodeType> GetCodeTypes()
    {
        var list = CodeDatas.DataTypeJson.ToObj2<List<CgCodeType>>();

        foreach (var item in list) item.DbType = item.DbTypeStr.ToObj2<List<CgDbTypeInfo>>();

        return list;
    }

    /// <summary>
    ///     获取实体类型信息
    /// </summary>
    /// <param name="types"></param>
    /// <param name="columnInfo"></param>
    /// <param name="dbtype"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    internal static CgSortTypeInfo GetEntityType(List<CgCodeType> types, DbColumnInfo columnInfo, DbType dbtype)
    {
        var typeInfo = types.FirstOrDefault(y =>
            y.DbType.Any(it => it.Name.Equals(columnInfo.DataType, StringComparison.OrdinalIgnoreCase)));
        if (typeInfo == null && (columnInfo.DataType + "").ToLower() == "double")
        {
            var type = types.First(it => it.Name == "decimal_18_4");
            return new CgSortTypeInfo { CodeType = type, DbTypeInfo = type.DbType[0] };
        }

        if (typeInfo == null)
        {
            var type = types.First(it => it.Name == "string100");
            return new CgSortTypeInfo { CodeType = type, DbTypeInfo = type.DbType[0] };
        }

        if (columnInfo.DataType == "json")
        {
            var type = types.First(it => it.Name.ToLower() == "string2000");
            return new CgSortTypeInfo { CodeType = type, DbTypeInfo = type.DbType[0] };
        }

        //如果是pgsql的情况下，使用DateTimeOffset
        if (columnInfo.DataType == "timestamptz" && dbtype == DbType.PostgreSQL)
        {
            var type = types.First(it => it.Name.ToLower() == "datetimeoffset");
            return new CgSortTypeInfo { CodeType = type, DbTypeInfo = type.DbType[0] };
        }
        //else if (columnInfo.DataType == "timestamp" && dbtype != SqlSugar.DbType.SqlServer)
        //{
        //    var type = types.First(it => it.Name.ToLower() == "datetime");
        //    return new SortTypeInfo() { CodeType = type, DbTypeInfo = type.DbType[0] };
        //}

        if (columnInfo.DataType == "timestamp" && dbtype != DbType.SqlServer)
        {
            var type = types.First(it => it.Name.ToLower() == "datetimeoffset");
            return new CgSortTypeInfo { CodeType = type, DbTypeInfo = type.DbType[0] };
        }

        var SortTypeInfoList = new List<CgSortTypeInfo>();
        foreach (var type in types)
        foreach (var cstype in type.DbType)
        {
            var item = new CgSortTypeInfo();
            item.DbTypeInfo = cstype;
            item.CodeType = type;
            item.Sort = GetSort(cstype, type, columnInfo, dbtype);
            SortTypeInfoList.Add(item);
        }

        var result = SortTypeInfoList.Where(it => it.CodeType.Name != "json_default").OrderByDescending(it => it.Sort)
            .FirstOrDefault();
        if (result == null)
            throw new Exception(
                $"没有匹配到类型{columnInfo.DataType} 来自 {columnInfo.TableName} 表 {columnInfo.DbColumnName} ，请到类型管理添加");
        if (result.CodeType.Name == "guid" && columnInfo.DataType == "char" && columnInfo.Length != 36)
            result = SortTypeInfoList.FirstOrDefault(it => it.CodeType.Name == "string100");
        if (dbtype == DbType.PostgreSQL)
            if (columnInfo.DataType == "bit")
            {
                var type = types.First(it => it.Name.ToLower() == "bytearray");
                return new CgSortTypeInfo { CodeType = type, DbTypeInfo = type.DbType[0] };
            }

        return result;
    }

    /// <summary>
    ///     匹配出最符合的类型
    /// </summary>
    /// <param name="cstype"></param>
    /// <param name="type"></param>
    /// <param name="columnInfo"></param>
    /// <param name="dbtype"></param>
    /// <returns></returns>
    internal static decimal GetSort(CgDbTypeInfo cstype, CgCodeType type, DbColumnInfo columnInfo, DbType dbtype)
    {
        decimal result = 0;
        if (columnInfo.DataType.Equals(cstype.Name, StringComparison.OrdinalIgnoreCase))
            result = result + 10000;
        else
            result = result - 30000;
        if (columnInfo.Length == Convert.ToInt32(cstype.Length))
            result = result + 5000;
        else if (columnInfo.Length > Convert.ToInt32(cstype.Length))
            result = result + ((columnInfo.Length - Convert.ToInt32(cstype.Length)) * -3);
        else
            result = result - 500;
        if (columnInfo.DecimalDigits == Convert.ToInt32(cstype.DecimalDigits))
            result = result + 5000;
        else if (columnInfo.DecimalDigits > Convert.ToInt32(cstype.DecimalDigits))
            result = result + ((columnInfo.DecimalDigits - Convert.ToInt32(cstype.DecimalDigits)) * -3);
        else
            result = result - 500;
        if (type.Name.Contains("nString") && columnInfo.DataType == "varchar") result = result - 500;
        return result;
    }


    /// <summary>
    ///     获取类名
    /// </summary>
    /// <param name="dbColumnName"></param>
    /// <param name="csharpNameType"></param>
    /// <param name="sqlSugarDbSettingOptions"></param>
    /// <returns></returns>
    internal static string GetCsharpName(string dbColumnName, CsharpNameType csharpNameType,
        SqlSugarDbSettingOptions sqlSugarDbSettingOptions)
    {
        //如果表名或者字段名没有启用 ，驼峰转大小写，，直接返回数据库名称
        if ((sqlSugarDbSettingOptions.EnableDbTableNameToUnderLine == false && csharpNameType == CsharpNameType.类名)
            || (sqlSugarDbSettingOptions.EnableDbColumnNameToUnderLine == false &&
                csharpNameType == CsharpNameType.属性名)) return dbColumnName;

        if (dbColumnName.Contains("_"))
        {
            dbColumnName = dbColumnName.TrimEnd('_');
            dbColumnName = dbColumnName.TrimStart('_');

            var array = dbColumnName.Split('_').Select(it => GetFirstUpper(it)).ToArray();
            return string.Join("", array);
        }

        return GetFirstUpper(dbColumnName);
    }

    /// <summary>
    ///     获取第一个字母大写
    /// </summary>
    /// <param name="dbColumnName"></param>
    /// <param name="islower"></param>
    /// <returns></returns>
    internal static string GetFirstUpper(string dbColumnName, bool islower = false)
    {
        if (dbColumnName == null)
            return null;
        if (islower)
            return dbColumnName[..1].ToUpper() + dbColumnName[1..].ToLower();
        if (dbColumnName.ToUpper() == dbColumnName)
            return dbColumnName[..1].ToUpper() + dbColumnName[1..].ToLower();
        return dbColumnName[..1].ToUpper() + dbColumnName[1..];
    }


    /// <summary>
    ///     获取 Entity 名称
    /// </summary>
    /// <param name="dbTableName">数据库表名</param>
    /// <param name="str">Sys_,替换的前缀</param>
    /// <returns></returns>
    internal static string GetDbTableNoPrefixEntity(string dbTableName, string str)
    {
        var s = dbTableName; //取到表名

        var arr = str.Split(',');
        foreach (var item in arr)
        {
            var kv = item.Split('=');
            if (kv.Length == 2)
            {
                var pre = kv[0].Trim();
                var replace = kv[1].Trim();
                if (string.IsNullOrWhiteSpace(pre)) continue; //被替换的部分为空，跳过
                s = s.Replace(pre, replace);
            }
            else
            {
                if (string.IsNullOrWhiteSpace(item)) continue; //被替换的部分为空，跳过
                s = s.Replace(item, "");
            }
        }

        return ToPascal(s);
    }

    /// <summary>
    ///     获取 Entity 名称
    /// </summary>
    /// <param name="dbTableName">数据库表名</param>
    /// <param name="str">Sys_=Sys,前缀=替换</param>
    /// <returns></returns>
    internal static string GetDbTableReplace(string dbTableName, string str)
    {
        var s = dbTableName; //取到表名

        var arr = str.Split(',');
        foreach (var item in arr)
        {
            var kv = item.Split('=');
            if (kv.Length != 2) continue;
            var pre = kv[0].Trim();
            var replace = kv[1].Trim();
            if (string.IsNullOrWhiteSpace(pre)) continue; //被替换的部分为空，跳过

            s = s.Replace(pre, replace);
        }

        return ToPascal(s);
    }

    /// <summary>
    ///     Pascal命名法（将首字母大写）
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    internal static string ToPascal(string str)
    {
        if (string.IsNullOrWhiteSpace(str)) return str;
        return str[..1].ToUpper() + str[1..];
    }

    /// <summary>
    ///     骆驼命名法（将首字母小写）
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    internal static string ToCamel(string str)
    {
        if (string.IsNullOrWhiteSpace(str)) return str;
        return str[..1].ToLower() + str[1..];
    }

    /// <summary>
    ///     将整个字符串小写
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    internal static string ToLower(string str)
    {
        return str?.ToLower() ?? "";
    }

    /// <summary>
    ///     判断是否是特殊类型
    /// </summary>
    /// <param name="column"></param>
    /// <returns></returns>
    internal static bool IsSpecialType(CgTableColumnsInfo column)
    {
        return Regex.IsMatch(column.ClassProperName, @"\[.+\]");
    }

    /// <summary>
    ///     获取类型
    /// </summary>
    /// <param name="column"></param>
    /// <returns></returns>
    internal static string GetType(CgTableColumnsInfo column)
    {
        var type = "string";
        if (IsSpecialType(column)) type = Regex.Match(column.ClassProperName, @"\[(.+)\]").Groups[1].Value;

        return type;
    }
}